package com.translation.assistant.manager

import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.huawei.agconnect.config.AGConnectServicesConfig
import com.huawei.hmf.tasks.OnFailureListener
import com.huawei.hmf.tasks.OnSuccessListener
import com.huawei.hms.mlsdk.common.MLApplication
import com.huawei.hms.mlsdk.model.download.MLLocalModelManager
import com.huawei.hms.mlsdk.model.download.MLModelDownloadListener
import com.huawei.hms.mlsdk.model.download.MLModelDownloadStrategy
import com.huawei.hms.mlsdk.translate.MLTranslatorFactory
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslateSetting
import com.huawei.hms.mlsdk.translate.local.MLLocalTranslatorModel
import com.translation.assistant.callback.DownloadStatusListener
import com.translation.assistant.callback.OnGetModelListener
import com.translation.assistant.callback.OnModelListener
import com.translation.assistant.callback.TextTranslateCallback
import com.translation.assistant.data.OfflineConstant
import com.translation.assistant.data.bean.Language
import com.translation.assistant.data.bean.TransResultBean
import com.translation.assistant.extension.mapping
import com.translation.assistant.utils.SensitiveWordsCheck
import java.util.concurrent.CountDownLatch
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

class OfflineTranslatorManager: LifecycleObserver {
    private var isDestroy: Boolean = false
    var isDownloading: Boolean = false
    var currentDownloadCode: String = ""
    val waitForDownloadList = ArrayList<String>()//等待下载的语言列表
    private var mContext: Context
    private var mExecutorService: ExecutorService? = null
    private var manager: MLLocalModelManager//模型管理器
    private var textTranslateCallback: TextTranslateCallback? = null
    private var downloadStatusListener: DownloadStatusListener? = null
    private var onDownloadModelListener: OnModelListener<Void>? = null
    private var onDeleteModelListener: OnModelListener<Void>? = null
    private var onGetModelListener: OnGetModelListener? = null
    private val downloadedList = HashSet<Language>()//HashSet元素不重复
    private val downloadedCodeList = HashSet<String>()//HashSet元素不重复
    private val notDownloadedList = HashSet<Language>()//HashSet元素不重复

    private constructor(context: Context) {
        Log.d("AssistantManager", "初始化")
        this.mContext = context
        manager = MLLocalModelManager.getInstance()
        setApiKey(context)
        getDownloadedModels(null)
    }

    //单例
    @SuppressLint("StaticFieldLeak")
    companion object {
        private var instance: OfflineTranslatorManager? = null
        fun getInstance(context: Context): OfflineTranslatorManager {
            if (instance == null) {
                synchronized(OfflineTranslatorManager::class.java) {
                    if (instance == null) {
                        instance = OfflineTranslatorManager(context)
                    }
                }
            }
            return instance!!
        }
    }

    /**
     * 页面销毁 终止回调
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        //isDestroy = true
    }

    fun cancelDownload() {
        waitForDownloadList.clear()
    }

    fun downloadAllModel() {
        val supportedLanguages = syncGetLocalAllLanguages()
        for (language in supportedLanguages) {
            downloadModelByCode(language)
        }
    }

    private fun setApiKey(context: Context) {
        val config = AGConnectServicesConfig.fromContext(context)
        MLApplication.getInstance().apiKey = config.getString("client/api_key")
    }

    /**
     * 执行文本离线翻译
     */
    fun translate(
        input: String,
        originLang: String = "zh",
        targetLang: String = "en",
        translateCallback: TextTranslateCallback? = null) {
        if(TextUtils.isEmpty(input)){
            if(!isDestroy){
                textTranslateCallback?.onFailed(1001,"The translated text is empty")
                translateCallback?.onFailed(1001,"The translated text is empty")
            }
            return
        }
        if(SensitiveWordsCheck.isViolated(input)){
            textTranslateCallback?.onFailed(1005,"内容违规。")
            translateCallback?.onFailed(1005,"内容违规。")
            return
        }

        //code映射
        val originLangCode = mapping(originLang)
        val targetLangCode = mapping(targetLang)
        Log.d("AssistantManager", "源语言：${originLangCode}，目标语言：${targetLangCode}")
        val supportedLanguages = syncGetLocalAllLanguages()
        if(!supportedLanguages.contains(originLangCode)){
            if(!isDestroy){

                textTranslateCallback?.onFailed(1002,"Unsupported language:${originLangCode}")
                translateCallback?.onFailed(1002,"Unsupported language:${originLangCode}")
            }
            return
        }
        if(!supportedLanguages.contains(targetLangCode)){
            if(!isDestroy){

                textTranslateCallback?.onFailed(1003,"Unsupported language:${targetLangCode}")
                translateCallback?.onFailed(1003,"Unsupported language:${targetLangCode}")
            }
            return
        }

        Log.d("AssistantManager", "创建离线翻译器")
        val setting = MLLocalTranslateSetting.Factory() // 设置源语言的编码，使用ISO 639-1标准。此设置为必选项，如果不设置，将可能出现问题。
            .setSourceLangCode(originLangCode) // 设置目标语言的编码，使用ISO 639-1标准。此设置为必选项，如果不设置，将可能出现问题。
            .setTargetLangCode(targetLangCode)
            .create()
        val mlLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
        Log.d("AssistantManager", "开始离线翻译")
        //异步方法
        val startTime = System.currentTimeMillis()
        mlLocalTranslator?.asyncTranslate(input)?.addOnSuccessListener(OnSuccessListener<String> { s ->
            Log.i("AssistantManager", "离线翻译耗时:${System.currentTimeMillis() - startTime}ms")
            mlLocalTranslator.stop()
            if(!isDestroy){

                if(SensitiveWordsCheck.isViolated(s)){
                    textTranslateCallback?.onFailed(1005,"内容违规。")
                    translateCallback?.onFailed(1005,"内容违规。")
                    return@OnSuccessListener
                }

                textTranslateCallback?.onCompleted(s, originLangCode, targetLangCode, true)
                translateCallback?.onCompleted(s, originLangCode, targetLangCode, true)
            }
        })?.addOnFailureListener(OnFailureListener { e ->
            Log.e("AssistantManager", "离线翻译失败: " + e.message)
            mlLocalTranslator.stop()
            if(!isDestroy){

                textTranslateCallback?.onFailed(1004, e.message)
                translateCallback?.onFailed(1004, e.message)
            }
        })

    }

    fun translate(
        input: String,
        originLang: String = "zh",
        targetLang: String = "en",
        index: Int,
        callback:(TransResultBean)->Unit) {
        if(TextUtils.isEmpty(input)){
            callback.invoke(TransResultBean(false, 1001, index, ""))
            return
        }
        //code映射
        val originLangCode = mapping(originLang)
        val targetLangCode = mapping(targetLang)
        Log.d("AssistantManager", "源语言：${originLangCode}，目标语言：${targetLangCode}")
        val supportedLanguages = syncGetLocalAllLanguages()
        if(!supportedLanguages.contains(originLangCode)){
            callback.invoke(TransResultBean(false, 1002, index, ""))
            return
        }
        if(!supportedLanguages.contains(targetLangCode)){
            callback.invoke(TransResultBean(false,1003, index, ""))
            return
        }

        Log.d("AssistantManager", "创建离线翻译器")
        val setting = MLLocalTranslateSetting.Factory() // 设置源语言的编码，使用ISO 639-1标准。此设置为必选项，如果不设置，将可能出现问题。
            .setSourceLangCode(originLangCode) // 设置目标语言的编码，使用ISO 639-1标准。此设置为必选项，如果不设置，将可能出现问题。
            .setTargetLangCode(targetLangCode)
            .create()
        val mlLocalTranslator = MLTranslatorFactory.getInstance().getLocalTranslator(setting)
        Log.d("AssistantManager", "开始离线翻译")
        //异步方法
        val startTime = System.currentTimeMillis()
        mlLocalTranslator?.asyncTranslate(input)?.addOnSuccessListener(OnSuccessListener<String> { s ->
            Log.i("AssistantManager", "离线翻译耗时:${System.currentTimeMillis() - startTime}ms")
            mlLocalTranslator.stop()
            callback.invoke(TransResultBean(false,10000, index, s))
        })?.addOnFailureListener(OnFailureListener { e ->
            Log.e("AssistantManager", "离线翻译失败: " + e.message)
            mlLocalTranslator.stop()
            callback.invoke(TransResultBean(false,1004, index, ""))
        })

    }

    /**
     * 异步方法获取本地离线翻译所支持的语种
     */
    /*fun getOfflineTranslatorLang(successLanguage: OnSuccessListener<Set<String>>) {
        //异步方法
        MLTranslateLanguage.getLocalAllLanguages().addOnSuccessListener(successLanguage)
    }*/

    /**
     * 同步方法获取本地离线翻译所支持的语种
     */
    fun syncGetLocalAllLanguages(): Set<String> {
        /*val supportedLanguages = MLTranslateLanguage.syncGetLocalAllLanguages()
        Log.d("AssistantManager", "同步方法获取本地离线翻译所支持的语种：${supportedLanguages}")
        return supportedLanguages*/
        return OfflineConstant.ALL_CODES
    }


    /**
     * 是否为已下载的模型
     */
    fun isModelDownloaded(language: Language): Boolean {
        return downloadedCodeList.contains(language.code)
    }

    fun downloadModel(
        language: Language,
        languageName: String = "",
        downloadModelListener: OnModelListener<Void>? = null,
    ) {
        downloadModelByCode(language.code, languageName, downloadModelListener)
    }

    /**
     * 下载语言包：sourceLangCode
     * 下载进度监听器：MLModelDownloadListener
     * 下载成功后回调：OnSuccessListener<Void>
     * 下载失败后回调：OnFailureListener
     */
    fun downloadModel(
        sourceLangCode: String,
        languageName: String = "",
        downloadModelListener: OnModelListener<Void>? = null,
    ) {
        //code映射
        val languageCode = mapping(sourceLangCode)
        downloadModelByCode(languageCode, languageName, downloadModelListener)
    }

    private fun downloadModelByCode(
        languageCode: String,
        languageName: String = "",
        downloadModelListener: OnModelListener<Void>? = null
    ) {
        downloadModelListener?.let {
            onDownloadModelListener = it
        }

        if(downloadedCodeList.contains(languageCode)){
            //已下载
            onDownloadModelListener?.onSuccess(currentDownloadCode, null)
            return
        }

        if(waitForDownloadList.contains(languageCode)){
            //确保列表元素不重复
            return
        }

        if(waitForDownloadList.size > 0){
            waitForDownloadList.add(languageCode)
        }else {
            waitForDownloadList.add(languageCode)
            //启动下载线程
            if (mExecutorService == null) {
                mExecutorService = Executors.newFixedThreadPool(1)
            }

            //一个接一个下载，下载完一个再下载下一个
            mExecutorService?.execute {
                while (waitForDownloadList.size > 0) {
                    isDownloading = true
                    downloadStatusListener?.onDownloadStatus(true)
                    val countDownLatch = CountDownLatch(1)
                    currentDownloadCode = waitForDownloadList[0]

                    // 获取模型管理器。
                    val model = MLLocalTranslatorModel.Factory(currentDownloadCode).create()
                    // 设置模型下载策略。
                    val downloadStrategy = MLModelDownloadStrategy.Factory()
                        //.needWifi() // 推荐wifi环境下下载。
                        .create()

                    //下载进度监听器
                    val modelDownloadListener =
                        MLModelDownloadListener { alreadyDownLength, totalLength ->
                            onDownloadModelListener?.onProcess(currentDownloadCode, alreadyDownLength, totalLength)
                        }
                    // 下载模型。
                    manager.downloadModel(model, downloadStrategy, modelDownloadListener)
                        .addOnSuccessListener{
                            countDownLatch.countDown()
                            OfflineConstant.ALL_LANGUAGES_MAP[currentDownloadCode]?.let { it1 ->
                                downloadedList.add(it1)
                                downloadedCodeList.add(it1.code)
                                notDownloadedList.remove(it1)
                            }
                            onDownloadModelListener?.onSuccess(currentDownloadCode, it)
                        }
                        .addOnFailureListener{
                            countDownLatch.countDown()
                            onDownloadModelListener?.onFailure(currentDownloadCode, it)
                        }

                    countDownLatch.await()
                    waitForDownloadList.remove(currentDownloadCode)
                }
                isDownloading = false
                downloadStatusListener?.onDownloadStatus(false)
            }
        }
    }

    fun deleteModel(languageCode: String, deleteModelListener: OnModelListener<Void>? = null) {
        deleteModelListener?.let {
            onDeleteModelListener = it
        }
        // 获取模型管理器。
        val model = MLLocalTranslatorModel.Factory(languageCode).create()
        manager.deleteModel(model).addOnSuccessListener {
            OfflineConstant.ALL_LANGUAGES_MAP[languageCode]?.let { it1 ->
                downloadedList.remove(it1)
                downloadedCodeList.remove(it1.code)
                notDownloadedList.add(it1)
            }
            onDeleteModelListener?.onSuccess(languageCode, it)
        }.addOnFailureListener {
            onDeleteModelListener?.onFailure(languageCode, it)
        }
    }

    fun getDownloadedModels(getModelListener: OnGetModelListener? = null) {
        getModelListener?.let {
            onGetModelListener = it
        }

        if(downloadedCodeList.size > 0 || notDownloadedList.size > 0){
            onGetModelListener?.onGetModelSuccess(downloadedList.toList(), notDownloadedList.toList())
            return
        }
        if(downloadedList.size + notDownloadedList.size == OfflineConstant.ALL_LANGUAGES_MAP.size) {
            Log.d("AssistantManager", "快捷途径获取已下载的模型列表")
            onGetModelListener?.onGetModelSuccess(downloadedList.toList(), notDownloadedList.toList())
        }else {
            Log.d("AssistantManager", "接口获取已下载的模型列表")
            // 获取已下载的模型列表。
            manager.getModels(MLLocalTranslatorModel::class.java)
                .addOnSuccessListener {result ->
                    val downloadCodeList = ArrayList<String>()
                    downloadCodeList.add("en")//英文在基础包中，无需下载
                    downloadCodeList.add("zh-HK")//英文在基础包中，无需下载
                    result?.let {
                        result.forEach {
                            downloadCodeList.add(it.languageCode)
                        }
                    }
                    val allLanguageMap = OfflineConstant.ALL_LANGUAGES_MAP
                    for(languageEntry in allLanguageMap){
                        if(downloadCodeList.contains(languageEntry.key)){
                            downloadedList.add(languageEntry.value)
                            downloadedCodeList.add(languageEntry.value.code)
                        }else {
                            if(languageEntry.key != "en" && languageEntry.key != "zh-HK"){
                                notDownloadedList.add(languageEntry.value)
                            }
                        }
                    }
                    onGetModelListener?.onGetModelSuccess(downloadedList.toList(), notDownloadedList.toList())
                }.addOnFailureListener {
                    onGetModelListener?.onGetModelFailure("", it)
                }
        }
    }

    fun checkLanguageCode(vararg mCodes: String, back:(Boolean)->Unit) {
        val codesList = arrayListOf<String>()
        mCodes.forEach {
            val code = mapping(it)
            codesList.add(code)
        }
        if(downloadedCodeList.size > 0 || notDownloadedList.size > 0){
            back.invoke(downloadedCodeList.containsAll(codesList))
        }else{
            getDownloadedModels(object :
                OnGetModelListener{
                override fun onGetModelSuccess(
                    downloadedModelList: List<Language>,
                    notDownloadedModelList: List<Language>,
                ) {
                    back.invoke(downloadedCodeList.containsAll(codesList))
                }

                override fun onGetModelFailure(var0: String, var1: Exception?) {
                    back.invoke(false)
                }

            })
        }
    }

    fun setTextTranslateCallback(textTranslateCallback: TextTranslateCallback?) {
        this.textTranslateCallback = textTranslateCallback
    }
    fun setOnDownloadModelListener(onDownloadModelListener: OnModelListener<Void>?) {
        this.onDownloadModelListener = onDownloadModelListener
    }
    fun setOnDeleteModelListener(onDeleteModelListener: OnModelListener<Void>?) {
        this.onDeleteModelListener = onDeleteModelListener
    }
    fun setOnGetModelListener(onGetModelListener: OnGetModelListener?) {
        this.onGetModelListener = onGetModelListener
    }
    fun setOnDownloadStatusListener(downloadStatusListener: DownloadStatusListener?) {
        this.downloadStatusListener = downloadStatusListener
    }
    fun clearAllListener(){
        textTranslateCallback = null
        onDownloadModelListener = null
        onDeleteModelListener = null
        onGetModelListener = null
        downloadStatusListener = null
    }
}